#ifndef SObject_H
#define SObject_H

#include "SIcons.h"
#include "SVisitor.h"

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

class SObject : /*public QObject,*/ public IVisitable
{
/*
	Q_OBJECT
	Q_PROPERTY(QString id READ id WRITE setId)
	Q_PROPERTY(QString text READ text WRITE setText)
	Q_PROPERTY(QString comment READ comment WRITE setComment)
*/

public:
	//static QString tagName() { return "var";}
	
public:
	DECLARE_ClientVisitable

	//SObject(QObject *parent = NULL);

	virtual bool isObject() const { return true;}
	virtual bool isGroupObjects() const { return false;}

	virtual void setId(const QString &v) { m_id = v;}
	QString id() const { return m_id;}
	
	virtual void setDisplayName(const QString &v) { m_displayName = v;}
	QString displayName() const { return m_displayName;}

	void setComment(const QString &v) { m_comment = v;}
	QString comment() const { return m_comment;}
	
	virtual void visit(IBaseVisitor &visitor) { visitor.visitObject(this); accept(visitor);}
	
private:
	QString m_id;
	QString m_displayName;
	QString m_comment;
};

typedef QSharedPointer<SObject> SObjectPtr;

///////////////////////////////////////////////////////////////////////////////

template<typename T> class SGroupObjects : public SObject
{
public:
	SGroupObjects() {}

	virtual bool isGroupObjects() const { return true;}

	int count() const { return m_list.count();}
	void clear() { m_list.clear(); m_hash.clear();}

	QSharedPointer<T> operator[](int i) const { return m_list[i];}

	QSharedPointer<T> findById(const QString &id) const;
	QSharedPointer<T> findByPtr(SObject *p) const;
	template<typename X> QSharedPointer<X> findById(const QString &id) const { return findById(id).dynamicCast<X>();}

	bool append(const QSharedPointer<T> &p);
	QSharedPointer<T> removeById(const QString &id);
	
public: // SObject
	virtual void visit(IBaseVisitor &visitor);

private:
	QList<QSharedPointer<T>> m_list;
	typedef QHash<QString,QSharedPointer<T>> SHash;
	SHash m_hash;
};

typedef SGroupObjects<SObject> SGroupObjectsGlobal;
typedef QSharedPointer<SGroupObjectsGlobal> SGroupObjectsGlobalPtr;

//
template<typename T> inline QSharedPointer<T> SGroupObjects<T>::findById(const QString &id_) const
{
	QString id = id_.toLower();

	if (m_hash.contains(id)) {
		return m_hash[id];
	}

	return QSharedPointer<T>();
}

//
template<typename T> inline QSharedPointer<T> SGroupObjects<T>::findByPtr(SObject *p) const
{
	if (p) {
		return findById(p->id());
	}
	return QSharedPointer<T>();
}

//
template<typename T> inline bool SGroupObjects<T>::append(const QSharedPointer<T> &p)
{
	if (!p) {
		return false;
	}
	QString id = p->id().toLower();
	if (findById(id)) {
		return false;
	}

	m_list.append(p);
	m_hash[id] = p;
	return true;
}

//
template<typename T> inline QSharedPointer<T> SGroupObjects<T>::removeById(const QString &id_)
{
	QString id = id_.toLower();
	QSharedPointer<T> p = findById(id);

	if (!p) {
		return p;
	}

	m_hash.remove(id);
	m_list.takeAt(m_list.indexOf(p));
	return p;
}

//
template<typename T> inline void SGroupObjects<T>::visit(IBaseVisitor &visitor)
{
	visitor.startGroupObjects(this);
	SObject::visit(visitor);

	for (int i = 0; i < count(); ++i) {
		SObjectPtr p = (*this)[i];
		p->visit(visitor);
	}

	visitor.endGroupObjects(this);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

class SAction : public QObject, public SObject
{
	Q_OBJECT

public:
	DECLARE_ClientVisitable

	SAction();

	QAction *action() const { return m_action;}

public:	// SObject
	virtual void setDisplayName(const QString &v);

private slots:
	void slotTriggered(bool checked);
	
private:
	QAction *m_action;
};

typedef QSharedPointer<SAction> SActionPtr;

///////////////////////////////////////////////////////////////////////////////

class SToolBar : public QObject, public SGroupObjects<SAction>
{
	Q_OBJECT

public:
	DECLARE_ClientVisitable

	SToolBar();
	~SToolBar();

	QToolBar *toolBar() const { return m_toolBar;}

public: // SGroupObjects<SAction>
	bool append(const SActionPtr &p);
	SActionPtr removeById(const QString &id);
	
private:
	QPointer<QToolBar> m_toolBar;
};

typedef QSharedPointer<SToolBar> SToolBarPtr;

///////////////////////////////////////////////////////////////////////////////

#endif
